home *** CD-ROM | disk | FTP | other *** search
Text File | 1991-11-24 | 54.0 KB | 2,601 lines |
- Newsgroups: comp.sources.misc
- From: jfh@rpp386.Cactus.ORG (John F Haugh II)
- Subject: v26i058: shadow - Shadow Password Suite, Part05/11
- Message-ID: <1991Nov24.185026.20213@sparky.imd.sterling.com>
- X-Md4-Signature: 1e593b97d7d71d67542aae12605dbe91
- Date: Sun, 24 Nov 1991 18:50:26 GMT
- Approved: kent@sparky.imd.sterling.com
-
- Submitted-by: jfh@rpp386.Cactus.ORG (John F Haugh II)
- Posting-number: Volume 26, Issue 58
- Archive-name: shadow/part05
- Environment: UNIX
- Supersedes: shadow-2: Volume 06, Issue 22-24
-
- #! /bin/sh
- # into a shell via "sh file" or similar. To overwrite existing files,
- # type "sh file -c".
- # The tool that generated this appeared in the comp.sources.unix newsgroup;
- # send mail to comp-sources-unix@uunet.uu.net if you want that tool.
- # Contents: age.c groupio.c newgrp.c pwio.c shadowio.c
- # Wrapped by kent@sparky on Sun Nov 24 11:03:42 1991
- PATH=/bin:/usr/bin:/usr/ucb ; export PATH
- echo If this archive is complete, you will see the following message:
- echo ' "shar: End of archive 5 (of 11)."'
- if test -f 'age.c' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'age.c'\"
- else
- echo shar: Extracting \"'age.c'\" \(6178 characters\)
- sed "s/^X//" >'age.c' <<'END_OF_FILE'
- X/*
- X * Copyright 1989, 1990, 1991, John F. Haugh II
- X * All rights reserved.
- X *
- X * Permission is granted to copy and create derivative works for any
- X * non-commercial purpose, provided this copyright notice is preserved
- X * in all copies of source code, or included in human readable form
- X * and conspicuously displayed on all copies of object code or
- X * distribution media.
- X */
- X
- X#include <sys/types.h>
- X#include <stdio.h>
- X#include <errno.h>
- X#include "config.h"
- X#include "pwd.h"
- X#include "shadow.h"
- X
- X#ifndef lint
- Xstatic char sccsid[] = "@(#)age.c 3.5 07:43:04 9/17/91";
- X#endif
- X
- X#define DAY (24L*3600L)
- X#ifdef ITI_AGING
- X#define SCALE (DAY)
- X#else
- X#define SCALE (1)
- X#endif
- X
- Xextern time_t time ();
- Xextern char *strdup();
- X
- X/*
- X * pwd_to_spwd - create entries for new spwd structure
- X *
- X * pwd_to_spwd() creates a new (struct spwd) containing the
- X * information in the pointed-to (struct passwd).
- X */
- X
- Xstatic struct spwd *
- Xpwd_to_spwd (pw)
- Xstruct passwd *pw;
- X{
- X static struct spwd tspwd;
- X struct spwd *sp = &tspwd;
- X time_t t;
- X
- X /*
- X * Nice, easy parts first. The name and passwd map directly
- X * from the old password structure to the new one.
- X */
- X
- X sp->sp_namp = strdup (pw->pw_name);
- X sp->sp_pwdp = strdup (pw->pw_passwd);
- X#ifdef ATT_AGE
- X
- X /*
- X * AT&T-style password aging maps the sp_min, sp_max, and
- X * sp_lstchg information from the pw_age field, which appears
- X * after the encrypted password.
- X */
- X
- X if (pw->pw_age[0]) {
- X t = (c64i (pw->pw_age[0]) * 7) * SCALE;
- X sp->sp_max = t;
- X
- X if (pw->pw_age[1]) {
- X t = (c64i (pw->pw_age[1]) * 7) * SCALE;
- X sp->sp_min = t;
- X } else
- X sp->sp_min = (10000L) * SCALE;
- X
- X if (pw->pw_age[1] && pw->pw_age[2]) {
- X t = (a64l (pw->pw_age + 2) * 7) * SCALE;
- X sp->sp_lstchg = t;
- X } else
- X sp->sp_lstchg = time ((time_t *) 0) / (DAY/SCALE);
- X } else {
- X sp->sp_min = 0;
- X sp->sp_max = (10000L * SCALE);
- X sp->sp_lstchg = time ((time_t *) 0) / (DAY/SCALE);
- X }
- X#else /* !ATT_AGE */
- X /*
- X * BSD does not use the pw_age field and has no aging information
- X * anywheres. The default values are used to initialize the
- X * fields which are in the missing pw_age field;
- X */
- X
- X sp->sp_min = 0;
- X sp->sp_max = (10000L * SCALE);
- X sp->sp_lstchg = time ((time_t *) 0) / (DAY/SCALE);
- X#endif /* ATT_AGE */
- X
- X /*
- X * These fields have no corresponding information in the password
- X * file. They are set to uninitialized values.
- X */
- X
- X sp->sp_warn = -1;
- X sp->sp_inact = -1;
- X sp->sp_expire = -1;
- X sp->sp_flag = -1;
- X
- X return sp;
- X}
- X
- X/*
- X * isexpired - determine if account is expired yet
- X *
- X * isexpired calculates the expiration date based on the
- X * password expiration criteria.
- X */
- X
- X/*ARGSUSED*/
- Xint
- Xisexpired (pw, sp)
- Xstruct passwd *pw;
- Xstruct spwd *sp;
- X{
- X long clock;
- X
- X clock = time ((time_t *) 0) / (DAY/SCALE);
- X
- X /*
- X * Quick and easy - there is an expired account field
- X * along with an inactive account field. Do the expired
- X * one first since it is worse.
- X */
- X
- X if (sp->sp_expire > 0 && sp->sp_expire < clock)
- X return 3;
- X
- X if (sp->sp_inact > 0 && sp->sp_lstchg > 0 && sp->sp_max > 0 &&
- X sp->sp_inact + sp->sp_lstchg + sp->sp_max < clock)
- X return 2;
- X
- X /*
- X * The last and max fields must be present for an account
- X * to have an expired password. A maximum of >10000 days
- X * is considered to be infinite.
- X */
- X
- X if (sp->sp_lstchg == -1 ||
- X sp->sp_max == -1 || sp->sp_max >= (10000L*SCALE))
- X return 0;
- X
- X /*
- X * Calculate today's day and the day on which the password
- X * is going to expire. If that date has already passed,
- X * the password has expired.
- X */
- X
- X if (sp->sp_lstchg + sp->sp_max < clock)
- X return 1;
- X
- X return 0;
- X}
- X
- X/*
- X * expire - force password change if password expired
- X *
- X * expire() calls /bin/passwd to change the user's password
- X * if it has expired.
- X */
- X
- Xint
- Xexpire (pw, sp)
- Xstruct passwd *pw;
- Xstruct spwd *sp;
- X{
- X int status;
- X int child;
- X int pid;
- X
- X if (! sp)
- X sp = pwd_to_spwd (pw);
- X
- X /*
- X * See if the user's password has expired, and if so
- X * force them to change their password.
- X */
- X
- X switch (status = isexpired (pw, sp)) {
- X case 0:
- X return 0;
- X case 1:
- X printf ("Your password has expired.");
- X break;
- X case 2:
- X printf ("Your password is inactive.");
- X break;
- X case 3:
- X printf ("Your login has expired.");
- X break;
- X }
- X
- X /*
- X * Setting the maximum valid period to less than the minimum
- X * valid period means that the minimum period will never
- X * occur while the password is valid, so the user can never
- X * change that password.
- X */
- X
- X if (status > 1 || sp->sp_max < sp->sp_min) {
- X puts (" Contact the system administrator.\n");
- X exit (1);
- X }
- X puts (" Choose a new one.\n");
- X fflush (stdout);
- X
- X /*
- X * Close all the files so that unauthorized access won't
- X * occur. This needs to be done anyway because those files
- X * might become stale after "passwd" is executed.
- X */
- X
- X endspent ();
- X endpwent ();
- X endsgent ();
- X endgrent ();
- X
- X /*
- X * Execute the /bin/passwd command. The exit status will be
- X * examined to see what the result is. If there are any
- X * errors the routine will exit. This forces the user to
- X * change their password before being able to use the account.
- X */
- X
- X if ((pid = fork ()) == 0) {
- X execl ("/bin/passwd", "passwd", pw->pw_name, (char *) 0);
- X puts ("Can't execute /bin/passwd");
- X exit (errno);
- X } else if (pid == -1) {
- X perror ("passwd");
- X exit (errno);
- X }
- X while ((child = wait (&status)) != pid && child != -1)
- X ;
- X
- X if (child == pid && status == 0)
- X return 1;
- X
- X exit (1);
- X /*NOTREACHED*/
- X}
- X
- X/*
- X * agecheck - see if warning is needed for password expiration
- X *
- X * agecheck sees how many days until the user's password is going
- X * to expire and warns the user of the pending password expiration.
- X */
- X
- Xvoid
- Xagecheck (pw, sp)
- Xstruct passwd *pw;
- Xstruct spwd *sp;
- X{
- X long clock = time ((long *) 0) / (DAY/SCALE);
- X long remain;
- X
- X if (! sp)
- X sp = pwd_to_spwd (pw);
- X
- X /*
- X * The last, max, and warn fields must be supported or the
- X * warning period cannot be calculated.
- X */
- X
- X if (sp->sp_lstchg == -1 || sp->sp_max == -1 || sp->sp_warn == -1)
- X return;
- X
- X if ((remain = (sp->sp_lstchg + sp->sp_max) - clock) <= sp->sp_warn) {
- X remain /= SCALE;
- X if (remain >= 0)
- X printf ("Your password will expire in %d %s.\n",
- X remain, remain == 1 ? "day":"days");
- X }
- X}
- END_OF_FILE
- if test 6178 -ne `wc -c <'age.c'`; then
- echo shar: \"'age.c'\" unpacked with wrong size!
- fi
- # end of 'age.c'
- fi
- if test -f 'groupio.c' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'groupio.c'\"
- else
- echo shar: Extracting \"'groupio.c'\" \(11029 characters\)
- sed "s/^X//" >'groupio.c' <<'END_OF_FILE'
- X/*
- X * Copyright 1990, 1991, John F. Haugh II
- X * All rights reserved.
- X *
- X * Permission is granted to copy and create derivative works for any
- X * non-commercial purpose, provided this copyright notice is preserved
- X * in all copies of source code, or included in human readable form
- X * and conspicuously displayed on all copies of object code or
- X * distribution media.
- X *
- X * This file implements a transaction oriented group database
- X * library. The group file is updated one entry at a time.
- X * After each transaction the file must be logically closed and
- X * transferred to the existing group file. The sequence of
- X * events is
- X *
- X * gr_lock -- lock group file
- X * gr_open -- logically open group file
- X * while transaction to process
- X * gr_(locate,update,remove) -- perform transaction
- X * done
- X * gr_close -- commit transactions
- X * gr_unlock -- remove group lock
- X */
- X
- X#include <sys/types.h>
- X#include <sys/stat.h>
- X#include <fcntl.h>
- X#include <errno.h>
- X#include <grp.h>
- X#include <stdio.h>
- X#ifdef BSD
- X#include <strings.h>
- X#else
- X#include <string.h>
- X#endif
- X
- X#ifndef lint
- Xstatic char sccsid[] = "@(#)groupio.c 3.9 08:45:35 9/12/91";
- X#endif
- X
- Xstatic int islocked;
- Xstatic int isopen;
- Xstatic int open_modes;
- Xstatic FILE *grfp;
- X
- Xstruct gr_file_entry {
- X char *grf_line;
- X int grf_changed;
- X struct group *grf_entry;
- X struct gr_file_entry *grf_next;
- X};
- X
- Xstatic struct gr_file_entry *grf_head;
- Xstatic struct gr_file_entry *grf_tail;
- Xstatic struct gr_file_entry *grf_cursor;
- Xstatic int gr_changed;
- Xstatic int lock_pid;
- X
- X#define GR_LOCK "/etc/group.lock"
- X#define GR_TEMP "/etc/grp.%d"
- X#define GROUP "/etc/group"
- X
- Xstatic char gr_filename[BUFSIZ] = GROUP;
- X
- Xextern char *strdup();
- Xextern struct group *sgetgrent();
- Xextern char *malloc();
- Xextern char *fgetsx();
- X
- X/*
- X * gr_dup - duplicate a group file entry
- X *
- X * gr_dup() accepts a pointer to a group file entry and
- X * returns a pointer to a group file entry in allocated
- X * memory.
- X */
- X
- Xstatic struct group *
- Xgr_dup (grent)
- Xstruct group *grent;
- X{
- X struct group *gr;
- X int i;
- X
- X if (! (gr = (struct group *) malloc (sizeof *gr)))
- X return 0;
- X
- X if ((gr->gr_name = strdup (grent->gr_name)) == 0 ||
- X (gr->gr_passwd = strdup (grent->gr_passwd)) == 0)
- X return 0;
- X
- X for (i = 0;grent->gr_mem[i];i++)
- X ;
- X
- X gr->gr_mem = (char **) malloc (sizeof (char *) * (i + 1));
- X for (i = 0;grent->gr_mem[i];i++)
- X if (! (gr->gr_mem[i] = strdup (grent->gr_mem[i])))
- X return 0;
- X
- X gr->gr_mem[i] = 0;
- X gr->gr_gid = grent->gr_gid;
- X
- X return gr;
- X}
- X
- X/*
- X * gr_free - free a dynamically allocated group file entry
- X *
- X * gr_free() frees up the memory which was allocated for the
- X * pointed to entry.
- X */
- X
- Xstatic void
- Xgr_free (grent)
- Xstruct group *grent;
- X{
- X int i;
- X
- X free (grent->gr_name);
- X free (grent->gr_passwd);
- X
- X for (i = 0;grent->gr_mem[i];i++)
- X free (grent->gr_mem[i]);
- X
- X free ((char *) grent->gr_mem);
- X}
- X
- X/*
- X * gr_name - change the name of the group file
- X */
- X
- Xint
- Xgr_name (name)
- Xchar *name;
- X{
- X if (isopen || strlen (name) > (BUFSIZ-10))
- X return -1;
- X
- X strcpy (gr_filename, name);
- X return 0;
- X}
- X
- X/*
- X * gr_lock - lock a group file
- X *
- X * gr_lock() encapsulates the lock operation. it returns
- X * TRUE or FALSE depending on the group file being
- X * properly locked. the lock is set by creating a semaphore
- X * file, GR_LOCK.
- X */
- X
- Xint
- Xgr_lock ()
- X{
- X int fd;
- X int pid;
- X int len;
- X char file[BUFSIZ];
- X char buf[32];
- X struct stat sb;
- X
- X if (islocked)
- X return 1;
- X
- X if (strcmp (gr_filename, GROUP) != 0)
- X return 0;
- X
- X /*
- X * Create a lock file which can be switched into place
- X */
- X
- X sprintf (file, GR_TEMP, lock_pid = getpid ());
- X if ((fd = open (file, O_CREAT|O_EXCL|O_WRONLY, 0600)) == -1)
- X return 0;
- X
- X sprintf (buf, "%d", lock_pid);
- X if (write (fd, buf, strlen (buf) + 1) != strlen (buf) + 1) {
- X (void) close (fd);
- X (void) unlink (file);
- X return 0;
- X }
- X close (fd);
- X
- X /*
- X * Simple case first -
- X * Link fails (in a sane environment ...) if the target
- X * exists already. So we try to switch in a new lock
- X * file. If that succeeds, we assume we have the only
- X * valid lock. Needs work for NFS where this assumption
- X * may not hold. The simple hack is to check the link
- X * count on the source file, which should be 2 iff the
- X * link =really= worked.
- X */
- X
- X if (link (file, GR_LOCK) == 0) {
- X if (stat (file, &sb) != 0)
- X return 0;
- X
- X if (sb.st_nlink != 2)
- X return 0;
- X
- X (void) unlink (file);
- X islocked = 1;
- X return 1;
- X }
- X
- X /*
- X * Invalid lock test -
- X * Open the lock file and see if the lock is valid.
- X * The PID of the lock file is checked, and if the PID
- X * is not valid, the lock file is removed. If the unlink
- X * of the lock file fails, it should mean that someone
- X * else is executing this code. They will get success,
- X * and we will fail.
- X */
- X
- X if ((fd = open (GR_LOCK, O_RDWR)) == -1 ||
- X (len = read (fd, buf, BUFSIZ)) <= 0) {
- X errno = EINVAL;
- X return 0;
- X }
- X buf[len] = '\0';
- X if ((pid = strtol (buf, (char **) 0, 10)) == 0) {
- X errno = EINVAL;
- X return 0;
- X }
- X if (kill (pid, 0) == 0) {
- X errno = EEXIST;
- X return 0;
- X }
- X if (unlink (GR_LOCK)) {
- X (void) close (fd);
- X (void) unlink (file);
- X
- X return 0;
- X }
- X
- X /*
- X * Re-try lock -
- X * The invalid lock has now been removed and I should
- X * be able to acquire a lock for myself just fine. If
- X * this fails there will be no retry. The link count
- X * test here makes certain someone executing the previous
- X * block of code didn't just remove the lock we just
- X * linked to.
- X */
- X
- X if (link (file, GR_LOCK) == 0) {
- X if (stat (file, &sb) != 0)
- X return 0;
- X
- X if (sb.st_nlink != 2)
- X return 0;
- X
- X (void) unlink (file);
- X islocked = 1;
- X return 1;
- X }
- X (void) unlink (file);
- X return 0;
- X}
- X
- X/*
- X * gr_unlock - logically unlock a group file
- X *
- X * gr_unlock() removes the lock which was set by an earlier
- X * invocation of gr_lock().
- X */
- X
- Xint
- Xgr_unlock ()
- X{
- X if (isopen) {
- X open_modes = O_RDONLY;
- X if (! gr_close ())
- X return 0;
- X }
- X if (islocked) {
- X islocked = 0;
- X if (lock_pid != getpid ())
- X return 0;
- X
- X (void) unlink (GR_LOCK);
- X return 1;
- X }
- X return 0;
- X}
- X
- X/*
- X * gr_open - open a group file
- X *
- X * gr_open() encapsulates the open operation. it returns
- X * TRUE or FALSE depending on the group file being
- X * properly opened.
- X */
- X
- Xint
- Xgr_open (mode)
- Xint mode;
- X{
- X char buf[8192];
- X char *cp;
- X struct gr_file_entry *grf;
- X struct group *grent;
- X
- X if (isopen || (mode != O_RDONLY && mode != O_RDWR))
- X return 0;
- X
- X if (mode != O_RDONLY && ! islocked &&
- X strcmp (gr_filename, GROUP) == 0)
- X return 0;
- X
- X if ((grfp = fopen (gr_filename, mode == O_RDONLY ? "r":"r+")) == 0)
- X return 0;
- X
- X grf_head = grf_tail = grf_cursor = 0;
- X gr_changed = 0;
- X
- X while (fgetsx (buf, sizeof buf, grfp) != (char *) 0) {
- X if (cp = strrchr (buf, '\n'))
- X *cp = '\0';
- X
- X if (! (grf = (struct gr_file_entry *) malloc (sizeof *grf)))
- X return 0;
- X
- X grf->grf_changed = 0;
- X grf->grf_line = strdup (buf);
- X if ((grent = sgetgrent (buf)) && ! (grent = gr_dup (grent)))
- X return 0;
- X
- X grf->grf_entry = grent;
- X
- X if (grf_head == 0) {
- X grf_head = grf_tail = grf;
- X grf->grf_next = 0;
- X } else {
- X grf_tail->grf_next = grf;
- X grf->grf_next = 0;
- X grf_tail = grf;
- X }
- X }
- X isopen++;
- X open_modes = mode;
- X
- X return 1;
- X}
- X
- X/*
- X * gr_close - close the group file
- X *
- X * gr_close() outputs any modified group file entries and
- X * frees any allocated memory.
- X */
- X
- Xint
- Xgr_close ()
- X{
- X char backup[BUFSIZ];
- X int mask;
- X int c;
- X int errors = 0;
- X FILE *bkfp;
- X struct gr_file_entry *grf;
- X struct stat sb;
- X
- X if (! isopen) {
- X errno = EINVAL;
- X return 0;
- X }
- X if (islocked && lock_pid != getpid ()) {
- X isopen = 0;
- X islocked = 0;
- X errno = EACCES;
- X return 0;
- X }
- X strcpy (backup, gr_filename);
- X strcat (backup, "-");
- X
- X if (open_modes == O_RDWR && gr_changed) {
- X mask = umask (0222);
- X if ((bkfp = fopen (backup, "w")) == 0) {
- X umask (mask);
- X return 0;
- X }
- X umask (mask);
- X fstat (fileno (grfp), &sb);
- X chown (backup, sb.st_uid, sb.st_gid);
- X
- X rewind (grfp);
- X while ((c = getc (grfp)) != EOF) {
- X if (putc (c, bkfp) == EOF) {
- X fclose (bkfp);
- X return 0;
- X }
- X }
- X if (fclose (bkfp))
- X return 0;
- X
- X isopen = 0;
- X (void) fclose (grfp);
- X
- X mask = umask (0222);
- X if (! (grfp = fopen (gr_filename, "w"))) {
- X umask (mask);
- X return 0;
- X }
- X umask (mask);
- X
- X for (grf = grf_head;! errors && grf;grf = grf->grf_next) {
- X if (grf->grf_changed) {
- X if (putgrent (grf->grf_entry, grfp))
- X errors++;
- X } else {
- X if (fputsx (grf->grf_line, grfp))
- X errors++;
- X
- X if (putc ('\n', grfp) == EOF)
- X errors++;
- X }
- X }
- X if (fflush (grfp))
- X errors++;
- X
- X if (errors) {
- X unlink (gr_filename);
- X link (backup, gr_filename);
- X unlink (backup);
- X return 0;
- X }
- X }
- X if (fclose (grfp))
- X return 0;
- X
- X grfp = 0;
- X
- X while (grf_head != 0) {
- X grf = grf_head;
- X grf_head = grf->grf_next;
- X
- X if (grf->grf_entry) {
- X gr_free (grf->grf_entry);
- X free ((char *) grf->grf_entry);
- X }
- X if (grf->grf_line)
- X free (grf->grf_line);
- X
- X free ((char *) grf);
- X }
- X grf_tail = 0;
- X isopen = 0;
- X return 1;
- X}
- X
- Xint
- Xgr_update (grent)
- Xstruct group *grent;
- X{
- X struct gr_file_entry *grf;
- X struct group *ngr;
- X
- X if (! isopen || open_modes == O_RDONLY) {
- X errno = EINVAL;
- X return 0;
- X }
- X for (grf = grf_head;grf != 0;grf = grf->grf_next) {
- X if (grf->grf_entry == 0)
- X continue;
- X
- X if (strcmp (grent->gr_name, grf->grf_entry->gr_name) != 0)
- X continue;
- X
- X if (! (ngr = gr_dup (grent)))
- X return 0;
- X else {
- X gr_free (grf->grf_entry);
- X *(grf->grf_entry) = *ngr;
- X }
- X grf->grf_changed = 1;
- X grf_cursor = grf;
- X return gr_changed = 1;
- X }
- X grf = (struct gr_file_entry *) malloc (sizeof *grf);
- X if (! (grf->grf_entry = gr_dup (grent)))
- X return 0;
- X
- X grf->grf_changed = 1;
- X grf->grf_next = 0;
- X grf->grf_line = 0;
- X
- X if (grf_tail)
- X grf_tail->grf_next = grf;
- X
- X if (! grf_head)
- X grf_head = grf;
- X
- X grf_tail = grf;
- X
- X return gr_changed = 1;
- X}
- X
- Xint
- Xgr_remove (name)
- Xchar *name;
- X{
- X struct gr_file_entry *grf;
- X struct gr_file_entry *ogrf;
- X
- X if (! isopen || open_modes == O_RDONLY) {
- X errno = EINVAL;
- X return 0;
- X }
- X for (ogrf = 0, grf = grf_head;grf != 0;
- X ogrf = grf, grf = grf->grf_next) {
- X if (! grf->grf_entry)
- X continue;
- X
- X if (strcmp (name, grf->grf_entry->gr_name) != 0)
- X continue;
- X
- X if (grf == grf_cursor)
- X grf_cursor = ogrf;
- X
- X if (ogrf != 0)
- X ogrf->grf_next = grf->grf_next;
- X else
- X grf_head = grf->grf_next;
- X
- X if (grf == grf_tail)
- X grf_tail = ogrf;
- X
- X return gr_changed = 1;
- X }
- X errno = ENOENT;
- X return 0;
- X}
- X
- Xstruct group *
- Xgr_locate (name)
- Xchar *name;
- X{
- X struct gr_file_entry *grf;
- X
- X if (! isopen) {
- X errno = EINVAL;
- X return 0;
- X }
- X for (grf = grf_head;grf != 0;grf = grf->grf_next) {
- X if (grf->grf_entry == 0)
- X continue;
- X
- X if (strcmp (name, grf->grf_entry->gr_name) == 0) {
- X grf_cursor = grf;
- X return grf->grf_entry;
- X }
- X }
- X errno = ENOENT;
- X return 0;
- X}
- X
- Xint
- Xgr_rewind ()
- X{
- X if (! isopen) {
- X errno = EINVAL;
- X return 0;
- X }
- X grf_cursor = 0;
- X return 1;
- X}
- X
- Xstruct group *
- Xgr_next ()
- X{
- X if (! isopen) {
- X errno = EINVAL;
- X return 0;
- X }
- X if (grf_cursor == 0)
- X grf_cursor = grf_head;
- X else
- X grf_cursor = grf_cursor->grf_next;
- X
- X while (grf_cursor) {
- X if (grf_cursor->grf_entry)
- X return grf_cursor->grf_entry;
- X
- X grf_cursor = grf_cursor->grf_next;
- X }
- X return 0;
- X}
- END_OF_FILE
- if test 11029 -ne `wc -c <'groupio.c'`; then
- echo shar: \"'groupio.c'\" unpacked with wrong size!
- fi
- # end of 'groupio.c'
- fi
- if test -f 'newgrp.c' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'newgrp.c'\"
- else
- echo shar: Extracting \"'newgrp.c'\" \(10165 characters\)
- sed "s/^X//" >'newgrp.c' <<'END_OF_FILE'
- X/*
- X * Copyright 1990, 1991, John F. Haugh II
- X * All rights reserved.
- X *
- X * Permission is granted to copy and create derivative works for any
- X * non-commercial purpose, provided this copyright notice is preserved
- X * in all copies of source code, or included in human readable form
- X * and conspicuously displayed on all copies of object code or
- X * distribution media.
- X */
- X
- X#include <sys/types.h>
- X#ifndef BSD
- X#include <string.h>
- X#else
- X#include <strings.h>
- X#endif
- X#include <stdio.h>
- X#include <grp.h>
- X#include "pwd.h"
- X#include <termio.h>
- X#ifdef SYS3
- X#include <sys/ioctl.h>
- X#endif
- X#include "config.h"
- X
- X#if !defined(BSD) && !defined(SUN)
- X#define bzero(p,n) memset(p, 0, n)
- X#endif
- X
- X#ifndef lint
- Xstatic char sccsid[] = "@(#)newgrp.c 3.7 08:43:39 9/12/91";
- X#endif
- X
- X#ifdef NGROUPS
- Xint ngroups;
- Xgid_t groups[NGROUPS];
- X#endif
- X
- Xchar *getpass();
- Xchar *getenv();
- Xchar *pw_encrypt();
- Xstruct passwd *pwd;
- Xstruct passwd *getpwuid();
- Xstruct passwd *getpwnam();
- X
- X#ifdef SHADOWPWD
- X#include "shadow.h"
- Xstruct spwd *spwd;
- Xstruct spwd *getspnam();
- X#endif
- X#ifdef SHADOWGRP
- Xstruct sgrp *sgrp;
- Xstruct sgrp *getsgnam();
- X#endif
- Xstruct group *grp;
- Xstruct group *getgrgid();
- Xstruct group *getgrnam();
- X
- Xchar *getlogin();
- Xchar *crypt();
- Xchar *getpass();
- Xchar *getenv();
- Xchar *pw_encrypt();
- Xvoid shell();
- X
- Xchar *name;
- Xchar *group;
- Xint gid;
- X
- Xchar *Prog;
- Xchar prog[BUFSIZ];
- Xchar base[BUFSIZ];
- Xchar passwd[BUFSIZ];
- Xchar *cpasswd;
- Xchar *salt;
- X
- X#ifndef MAXENV
- X#define MAXENV 64
- X#endif
- X
- Xchar *newenvp[MAXENV];
- Xint newenvc = 0;
- Xint maxenv = MAXENV;
- X
- X/*
- X * usage - print command usage message
- X */
- X
- Xusage ()
- X{
- X fprintf (stderr, "usage: newgrp [ - ] [ group ]\n");
- X}
- X
- X/*
- X * newgrp - change the invokers current real and effective group id
- X */
- X
- Xmain (argc, argv, envp)
- Xint argc;
- Xchar **argv;
- Xchar **envp;
- X{
- X int initflag = 0;
- X int needspasswd = 0;
- X int i;
- X char *cp;
- X
- X /*
- X * save my name for error messages and save my real gid incase
- X * of errors. if there is an error i have to exec a new login
- X * shell for the user since her old shell won't have fork'd to
- X * create the process. skip over the program name to the next
- X * command line argument.
- X */
- X
- X Prog = argv[0];
- X gid = getgid ();
- X argc--; argv++;
- X
- X /*
- X * let me parse the command line first. the only recognized
- X * option is a "-", which indicates that the shell is to perform
- X * the same initialization it does at login time. the next
- X * argument, if present, must be the new group name. any
- X * remaining arguments will be used to execute a command for
- X * the user as the named group. if the group name isn't present
- X * i just use the login group id of this user.
- X */
- X
- X if (argc > 0 && argv[0][0] == '-') {
- X if (strcmp (argv[0], "-") == 0) {
- X initflag = 1;
- X argc--; argv++;
- X } else {
- X usage ();
- X goto failure;
- X }
- X }
- X#ifdef NGROUPS
- X
- X /*
- X * get the current users groupset. the new group will be
- X * added to the concurrent groupset if there is room, otherwise
- X * you get a nasty message but at least your real and effective
- X * group id's are set.
- X */
- X
- X ngroups = getgroups (groups);
- X#endif
- X
- X /*
- X * now i get to determine my current name. i do this to validate
- X * my access to the requested group. the validation works like
- X * this -
- X * 1) get the name associated with my current user id
- X * 2) get my login name, as told by getlogin().
- X * 3) if they match, my name is the login name
- X * 4) if they don't match, my name is the name in the
- X * password file.
- X *
- X * this isn't perfect, but it works more often then not.
- X */
- X
- X pwd = getpwuid (getuid ());
- X
- X if (! (name = getlogin ()) || strcmp (name, pwd->pw_name) != 0)
- X name = pwd->pw_name;
- X
- X if (! (pwd = getpwnam (name))) {
- X fprintf (stderr, "unknown user: %s\n", name);
- X exit (1);
- X }
- X
- X /*
- X * now we determine the name of the new group which she wishes
- X * to become a member of. the password file entry for her
- X * current user id has been gotten. if there is no optional
- X * group argument she will have her real and effective group id
- X * set to the value from her password file entry. otherwise
- X * we validate her access to the specified group.
- X */
- X
- X if (argv[0] != (char *) 0) {
- X
- X /*
- X * start by getting the entry for the requested group.
- X */
- X
- X if (! (grp = getgrnam (group = argv[0]))) {
- X fprintf (stderr, "unknown group: %s\n", group);
- X goto failure;
- X }
- X#ifdef SHADOWGRP
- X sgrp = getsgnam (group);
- X#endif
- X
- X /*
- X * see if she is a member of this group.
- X */
- X
- X for (i = 0;grp->gr_mem[i];i++)
- X if (strcmp (name, grp->gr_mem[i]) == 0)
- X break;
- X
- X /*
- X * if she isn't a member, she needs to provide the
- X * group password. if there is no group password, she
- X * will be denied access anyway.
- X */
- X
- X if (grp->gr_mem[i] == (char *) 0)
- X needspasswd = 1;
- X
- X#ifdef SHADOWGRP
- X if (sgrp) {
- X
- X /*
- X * Do the tests again with the shadow group entry.
- X */
- X
- X for (i = 0;sgrp->sg_mem[i];i++)
- X if (strcmp (name, sgrp->sg_mem[i]) == 0)
- X break;
- X
- X needspasswd = sgrp->sg_mem[i] == 0;
- X }
- X#endif
- X#ifdef SHADOWPWD
- X
- X /*
- X * if she does not have either a shadowed password,
- X * or a regular password, and the group has a password,
- X * she needs to give the group password.
- X */
- X
- X if (spwd = getspnam (name)) {
- X if (spwd->sp_pwdp[0] == '\0' && grp->gr_passwd[0])
- X needspasswd = 1;
- X#ifdef SHADOWGRP
- X if (spwd->sp_pwdp[0] == '\0' && sgrp != 0)
- X needspasswd = sgrp->sg_passwd[0] != '\0';
- X#endif
- X } else {
- X if (pwd->pw_passwd[0] == '\0' && grp->gr_passwd[0])
- X needspasswd = 1;
- X#ifdef SHADOWGRP
- X if (pwd->pw_passwd[0] == '\0' && sgrp != 0)
- X needspasswd = sgrp->sg_passwd[0] != '\0';
- X#endif
- X }
- X#else
- X
- X /*
- X * if she does not have a regular password she will have
- X * to give the group password, if one exists.
- X */
- X
- X if (pwd->pw_passwd[0] == '\0' && grp->gr_passwd[0])
- X needspasswd = 1;
- X#ifdef SHADOWGRP
- X if (pwd->pw_passwd[0] == '\0' && sgrp != 0)
- X needspasswd = sgrp->sg_passwd[0] != '\0';
- X#endif
- X#endif
- X
- X /*
- X * Skip over the user name
- X */
- X
- X argc--; argv++;
- X
- X } else {
- X
- X /*
- X * get the group file entry for her login group id.
- X * the entry must exist, simply to be annoying.
- X */
- X
- X if (! (grp = getgrgid (pwd->pw_gid))) {
- X fprintf (stderr, "unknown gid: %d\n", pwd->pw_gid);
- X goto failure;
- X }
- X }
- X
- X /*
- X * now i see about letting her into the group she requested.
- X * if she is the root user, i'll let her in without having to
- X * prompt for the password. otherwise i ask for a password
- X * if she flunked one of the tests above. note that she
- X * won't have to provide the password to her login group even
- X * if she isn't listed as a member.
- X */
- X
- X if (getuid () != 0 && needspasswd) {
- X char *encrypted;
- X
- X encrypted = grp->gr_passwd;
- X#ifdef SHADOWGRP
- X if (sgrp)
- X encrypted = sgrp->sg_passwd;
- X#endif
- X passwd[0] = '\0';
- X
- X if (encrypted[0]) {
- X
- X /*
- X * get the password from her, and set the salt for
- X * the decryption from the group file.
- X */
- X
- X if (! (cp = getpass ("Password:")))
- X goto failure;
- X
- X strcpy (passwd, cp);
- X bzero (cp, strlen (cp));
- X salt = encrypted;
- X } else {
- X
- X /*
- X * there is no password, print out "Sorry" and give up
- X */
- X
- X fputs ("Sorry\n", stderr);
- X goto failure;
- X }
- X
- X /*
- X * encrypt the key she gave us using the salt from
- X * the password in the group file. the result of
- X * this encryption must match the previously
- X * encrypted value in the file.
- X */
- X
- X cpasswd = pw_encrypt (passwd, salt);
- X bzero (passwd, sizeof passwd);
- X
- X if (strcmp (cpasswd, encrypted) != 0) {
- X fputs ("Sorry\n", stderr);
- X goto failure;
- X }
- X }
- X
- X /*
- X * all successful validations pass through this point. the
- X * group id will be set, and the group added to the concurrent
- X * groupset.
- X */
- X
- X gid = grp->gr_gid;
- X#ifdef NGROUPS
- X
- X /*
- X * i am going to try to add her new group id to her concurrent
- X * group set. if the group id is already present i'll just
- X * skip this part. if the group doesn't fit, i'll complain
- X * loudly and skip this part ...
- X */
- X
- X for (i = 0;i < ngroups;i++) {
- X if (gid == groups[i])
- X break;
- X }
- X if (i == ngroups) {
- X if (ngroups == NGROUPS) {
- X fprintf (stderr, "too many groups\n");
- X } else {
- X groups[ngroups++] = gid;
- X if (setgroups (ngroups, groups)) {
- X fprintf (stderr, "%s: ", Prog);
- X perror ("unable to set groups");
- X }
- X }
- X }
- X#endif
- X
- X /*
- X * this is where all failures land. the group id will not
- X * have been set, so the setgid() below will set me to the
- X * original group id i had when i was invoked.
- X */
- X
- Xfailure:
- X
- X /*
- X * i set her group id either to the value she requested, or
- X * to the original value. i have to go back to the original
- X * because she no longer has a shell running.
- X */
- X
- X if (setgid (gid))
- X perror ("setgid");
- X
- X if (setuid (getuid ()))
- X perror ("setuid");
- X
- X /*
- X * i have to get the pathname of her login shell. as a favor
- X * i'll try her environment for a $SHELL value first, and
- X * then try the password file entry.
- X */
- X
- X if (! initflag && (cp = getenv ("SHELL")))
- X strncpy (prog, cp, sizeof prog);
- X else if (pwd->pw_shell && pwd->pw_shell[0])
- X strncpy (prog, pwd->pw_shell, sizeof prog);
- X else
- X strcpy (prog, "/bin/sh");
- X
- X /*
- X * now i try to find the basename of the login shell. this
- X * will become argv[0] of the spawned command.
- X */
- X
- X if (cp = strrchr (prog, '/'))
- X cp++;
- X else
- X cp = prog;
- X
- X /*
- X * to have the shell perform login processing i will set the
- X * first character in the first argument to a "-".
- X */
- X
- X if (initflag)
- X strcat (strcpy (base, "-"), cp);
- X else
- X strcpy (base, cp);
- X
- X#ifdef SHADOWPWD
- X endspent ();
- X#endif
- X#ifdef SHADOWGRP
- X endsgent ();
- X#endif
- X endpwent ();
- X endgrent ();
- X
- X /*
- X * switch back to her home directory if i am doing login
- X * initialization.
- X */
- X
- X if (initflag) {
- X chdir (pwd->pw_dir);
- X while (*envp) {
- X if (strncmp (*envp, "PATH=", 5) == 0 ||
- X strncmp (*envp, "HOME=", 5) == 0 ||
- X strncmp (*envp, "SHELL=", 6) == 0)
- X addenv (*envp);
- X
- X envp++;
- X }
- X } else {
- X while (*envp)
- X addenv (*envp++);
- X }
- X
- X /*
- X * exec the login shell and go away. if there were additional
- X * arguments, use those instead.
- X */
- X
- X if (argc > 0) {
- X argv--;
- X argv[0] = prog;
- X execve (argv[0], argv, newenvp);
- X perror (argv[0]);
- X _exit (127);
- X }
- X shell (prog, base);
- X /*NOTREACHED*/
- X}
- END_OF_FILE
- if test 10165 -ne `wc -c <'newgrp.c'`; then
- echo shar: \"'newgrp.c'\" unpacked with wrong size!
- fi
- # end of 'newgrp.c'
- fi
- if test -f 'pwio.c' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'pwio.c'\"
- else
- echo shar: Extracting \"'pwio.c'\" \(11226 characters\)
- sed "s/^X//" >'pwio.c' <<'END_OF_FILE'
- X/*
- X * Copyright 1990, 1991, John F. Haugh II
- X * All rights reserved.
- X *
- X * Permission is granted to copy and create derivative works for any
- X * non-commercial purpose, provided this copyright notice is preserved
- X * in all copies of source code, or included in human readable form
- X * and conspicuously displayed on all copies of object code or
- X * distribution media.
- X *
- X * This file implements a transaction oriented password database
- X * library. The password file is updated one entry at a time.
- X * After each transaction the file must be logically closed and
- X * transferred to the existing password file. The sequence of
- X * events is
- X *
- X * pw_lock -- lock password file
- X * pw_open -- logically open password file
- X * while transaction to process
- X * pw_(locate,update,remove) -- perform transaction
- X * done
- X * pw_close -- commit transactions
- X * pw_unlock -- remove password lock
- X */
- X
- X#include <sys/types.h>
- X#include <sys/stat.h>
- X#include <fcntl.h>
- X#include <errno.h>
- X#include "pwd.h"
- X#include <stdio.h>
- X
- X#ifdef BSD
- X# include <strings.h>
- X#else
- X# include <string.h>
- X#endif
- X
- X#ifndef lint
- Xstatic char sccsid[] = "@(#)pwio.c 3.9 08:46:13 9/12/91";
- X#endif
- X
- Xstatic int islocked;
- Xstatic int isopen;
- Xstatic int open_modes;
- Xstatic FILE *pwfp;
- X
- Xstruct pw_file_entry {
- X char *pwf_line;
- X int pwf_changed;
- X struct passwd *pwf_entry;
- X struct pw_file_entry *pwf_next;
- X};
- X
- Xstatic struct pw_file_entry *pwf_head;
- Xstatic struct pw_file_entry *pwf_tail;
- Xstatic struct pw_file_entry *pwf_cursor;
- Xstatic int pw_changed;
- Xstatic int lock_pid;
- X
- X#define PW_LOCK "/etc/passwd.lock"
- X#define PW_TEMP "/etc/pwd.%d"
- X#define PASSWD "/etc/passwd"
- X
- Xstatic char pw_filename[BUFSIZ] = PASSWD;
- X
- Xextern int fputs();
- Xextern char *fgets();
- Xextern char *strdup();
- Xextern char *malloc();
- Xextern struct passwd *sgetpwent();
- X
- X/*
- X * pw_dup - duplicate a password file entry
- X *
- X * pw_dup() accepts a pointer to a password file entry and
- X * returns a pointer to a password file entry in allocated
- X * memory.
- X */
- X
- Xstatic struct passwd *
- Xpw_dup (pwent)
- Xstruct passwd *pwent;
- X{
- X struct passwd *pw;
- X
- X if (! (pw = (struct passwd *) malloc (sizeof *pw)))
- X return 0;
- X
- X if ((pw->pw_name = strdup (pwent->pw_name)) == 0 ||
- X (pw->pw_passwd = strdup (pwent->pw_passwd)) == 0 ||
- X#ifdef ATT_AGE
- X (pw->pw_age = strdup (pwent->pw_age)) == 0 ||
- X#endif /* ATT_AGE */
- X#ifdef ATT_COMMENT
- X (pw->pw_comment = strdup (pwent->pw_comment)) == 0 ||
- X#endif /* ATT_COMMENT */
- X (pw->pw_gecos = strdup (pwent->pw_gecos)) == 0 ||
- X (pw->pw_dir = strdup (pwent->pw_dir)) == 0 ||
- X (pw->pw_shell = strdup (pwent->pw_shell)) == 0)
- X return 0;
- X
- X pw->pw_uid = pwent->pw_uid;
- X pw->pw_gid = pwent->pw_gid;
- X
- X return pw;
- X}
- X
- X/*
- X * pw_free - free a dynamically allocated password file entry
- X *
- X * pw_free() frees up the memory which was allocated for the
- X * pointed to entry.
- X */
- X
- Xstatic void
- Xpw_free (pwent)
- Xstruct passwd *pwent;
- X{
- X free (pwent->pw_name);
- X free (pwent->pw_passwd);
- X free (pwent->pw_gecos);
- X free (pwent->pw_dir);
- X free (pwent->pw_shell);
- X}
- X
- X/*
- X * pw_name - change the name of the password file
- X */
- X
- Xint
- Xpw_name (name)
- Xchar *name;
- X{
- X if (isopen || strlen (name) > (BUFSIZ-10))
- X return -1;
- X
- X strcpy (pw_filename, name);
- X return 0;
- X}
- X
- X/*
- X * pw_lock - lock a password file
- X *
- X * pw_lock() encapsulates the lock operation. it returns
- X * TRUE or FALSE depending on the password file being
- X * properly locked. the lock is set by creating a semaphore
- X * file, PW_LOCK.
- X */
- X
- Xint
- Xpw_lock ()
- X{
- X int fd;
- X int pid;
- X int len;
- X char file[BUFSIZ];
- X char buf[32];
- X struct stat sb;
- X
- X if (islocked)
- X return 1;
- X
- X if (strcmp (pw_filename, PASSWD) != 0)
- X return 0;
- X
- X /*
- X * Create a lock file which can be switched into place
- X */
- X
- X sprintf (file, PW_TEMP, lock_pid = getpid ());
- X if ((fd = open (file, O_CREAT|O_EXCL|O_WRONLY, 0600)) == -1)
- X return 0;
- X
- X sprintf (buf, "%d", lock_pid);
- X if (write (fd, buf, strlen (buf) + 1) != strlen (buf) + 1) {
- X (void) close (fd);
- X (void) unlink (file);
- X return 0;
- X }
- X close (fd);
- X
- X /*
- X * Simple case first -
- X * Link fails (in a sane environment ...) if the target
- X * exists already. So we try to switch in a new lock
- X * file. If that succeeds, we assume we have the only
- X * valid lock. Needs work for NFS where this assumption
- X * may not hold. The simple hack is to check the link
- X * count on the source file, which should be 2 iff the
- X * link =really= worked.
- X */
- X
- X if (link (file, PW_LOCK) == 0) {
- X if (stat (file, &sb) != 0)
- X return 0;
- X
- X if (sb.st_nlink != 2)
- X return 0;
- X
- X (void) unlink (file);
- X islocked = 1;
- X return 1;
- X }
- X
- X /*
- X * Invalid lock test -
- X * Open the lock file and see if the lock is valid.
- X * The PID of the lock file is checked, and if the PID
- X * is not valid, the lock file is removed. If the unlink
- X * of the lock file fails, it should mean that someone
- X * else is executing this code. They will get success,
- X * and we will fail.
- X */
- X
- X if ((fd = open (PW_LOCK, O_RDWR)) == -1 ||
- X (len = read (fd, buf, BUFSIZ)) <= 0) {
- X errno = EINVAL;
- X return 0;
- X }
- X buf[len] = '\0';
- X if ((pid = strtol (buf, (char **) 0, 10)) == 0) {
- X errno = EINVAL;
- X return 0;
- X }
- X if (kill (pid, 0) == 0) {
- X errno = EEXIST;
- X return 0;
- X }
- X if (unlink (PW_LOCK)) {
- X (void) close (fd);
- X (void) unlink (file);
- X
- X return 0;
- X }
- X
- X /*
- X * Re-try lock -
- X * The invalid lock has now been removed and I should
- X * be able to acquire a lock for myself just fine. If
- X * this fails there will be no retry. The link count
- X * test here makes certain someone executing the previous
- X * block of code didn't just remove the lock we just
- X * linked to.
- X */
- X
- X if (link (file, PW_LOCK) == 0) {
- X if (stat (file, &sb) != 0)
- X return 0;
- X
- X if (sb.st_nlink != 2)
- X return 0;
- X
- X (void) unlink (file);
- X islocked = 1;
- X return 1;
- X }
- X (void) unlink (file);
- X return 0;
- X}
- X
- X/*
- X * pw_unlock - logically unlock a password file
- X *
- X * pw_unlock() removes the lock which was set by an earlier
- X * invocation of pw_lock().
- X */
- X
- Xint
- Xpw_unlock ()
- X{
- X if (isopen) {
- X open_modes = O_RDONLY;
- X if (! pw_close ())
- X return 0;
- X }
- X if (islocked) {
- X islocked = 0;
- X if (lock_pid != getpid ())
- X return 0;
- X
- X (void) unlink (PW_LOCK);
- X return 1;
- X }
- X return 0;
- X}
- X
- X/*
- X * pw_open - open a password file
- X *
- X * pw_open() encapsulates the open operation. it returns
- X * TRUE or FALSE depending on the password file being
- X * properly opened.
- X */
- X
- Xint
- Xpw_open (mode)
- Xint mode;
- X{
- X char buf[8192];
- X char *cp;
- X struct pw_file_entry *pwf;
- X struct passwd *pwent;
- X
- X if (isopen || (mode != O_RDONLY && mode != O_RDWR))
- X return 0;
- X
- X if (mode != O_RDONLY && ! islocked &&
- X strcmp (pw_filename, PASSWD) == 0)
- X return 0;
- X
- X if ((pwfp = fopen (pw_filename, mode == O_RDONLY ? "r":"r+")) == 0)
- X return 0;
- X
- X pwf_head = pwf_tail = pwf_cursor = 0;
- X pw_changed = 0;
- X
- X while (fgets (buf, sizeof buf, pwfp) != (char *) 0) {
- X if (cp = strrchr (buf, '\n'))
- X *cp = '\0';
- X
- X if (! (pwf = (struct pw_file_entry *) malloc (sizeof *pwf)))
- X return 0;
- X
- X pwf->pwf_changed = 0;
- X pwf->pwf_line = strdup (buf);
- X if ((pwent = sgetpwent (buf)) && ! (pwent = pw_dup (pwent)))
- X return 0;
- X
- X pwf->pwf_entry = pwent;
- X
- X if (pwf_head == 0) {
- X pwf_head = pwf_tail = pwf;
- X pwf->pwf_next = 0;
- X } else {
- X pwf_tail->pwf_next = pwf;
- X pwf->pwf_next = 0;
- X pwf_tail = pwf;
- X }
- X }
- X isopen++;
- X open_modes = mode;
- X
- X return 1;
- X}
- X
- X/*
- X * pw_close - close the password file
- X *
- X * pw_close() outputs any modified password file entries and
- X * frees any allocated memory.
- X */
- X
- Xint
- Xpw_close ()
- X{
- X char backup[BUFSIZ];
- X int mask;
- X int c;
- X int errors = 0;
- X FILE *bkfp;
- X struct pw_file_entry *pwf;
- X struct stat sb;
- X
- X if (! isopen) {
- X errno = EINVAL;
- X return 0;
- X }
- X if (islocked && lock_pid != getpid ()) {
- X isopen = 0;
- X islocked = 0;
- X errno = EACCES;
- X return 0;
- X }
- X strcpy (backup, pw_filename);
- X strcat (backup, "-");
- X
- X if (open_modes == O_RDWR && pw_changed) {
- X mask = umask (0222);
- X if ((bkfp = fopen (backup, "w")) == 0) {
- X umask (mask);
- X return 0;
- X }
- X umask (mask);
- X fstat (fileno (pwfp), &sb);
- X chown (backup, sb.st_uid, sb.st_gid);
- X
- X rewind (pwfp);
- X while ((c = getc (pwfp)) != EOF) {
- X if (putc (c, bkfp) == EOF) {
- X fclose (bkfp);
- X return 0;
- X }
- X }
- X if (fclose (bkfp))
- X return 0;
- X
- X isopen = 0;
- X (void) fclose (pwfp);
- X
- X mask = umask (0222);
- X if (! (pwfp = fopen (pw_filename, "w"))) {
- X umask (mask);
- X return 0;
- X }
- X umask (mask);
- X
- X for (pwf = pwf_head;errors == 0 && pwf;pwf = pwf->pwf_next) {
- X if (pwf->pwf_changed) {
- X if (putpwent (pwf->pwf_entry, pwfp))
- X errors++;
- X } else {
- X if (fputs (pwf->pwf_line, pwfp) == EOF)
- X errors++;
- X if (putc ('\n', pwfp) == EOF)
- X errors++;
- X }
- X }
- X if (fflush (pwfp))
- X errors++;
- X
- X if (errors) {
- X unlink (pw_filename);
- X link (backup, pw_filename);
- X unlink (backup);
- X return 0;
- X }
- X }
- X if (fclose (pwfp))
- X return 0;
- X
- X pwfp = 0;
- X
- X while (pwf_head != 0) {
- X pwf = pwf_head;
- X pwf_head = pwf->pwf_next;
- X
- X if (pwf->pwf_entry) {
- X pw_free (pwf->pwf_entry);
- X free (pwf->pwf_entry);
- X }
- X if (pwf->pwf_line)
- X free (pwf->pwf_line);
- X
- X free (pwf);
- X }
- X pwf_tail = 0;
- X isopen = 0;
- X return 1;
- X}
- X
- Xint
- Xpw_update (pwent)
- Xstruct passwd *pwent;
- X{
- X struct pw_file_entry *pwf;
- X struct passwd *npw;
- X
- X if (! isopen || open_modes == O_RDONLY) {
- X errno = EINVAL;
- X return 0;
- X }
- X for (pwf = pwf_head;pwf != 0;pwf = pwf->pwf_next) {
- X if (pwf->pwf_entry == 0)
- X continue;
- X
- X if (strcmp (pwent->pw_name, pwf->pwf_entry->pw_name) != 0)
- X continue;
- X
- X if (! (npw = pw_dup (pwent)))
- X return 0;
- X else {
- X pw_free (pwf->pwf_entry);
- X *(pwf->pwf_entry) = *npw;
- X }
- X pwf->pwf_changed = 1;
- X pwf_cursor = pwf;
- X return pw_changed = 1;
- X }
- X pwf = (struct pw_file_entry *) malloc (sizeof *pwf);
- X if (! (pwf->pwf_entry = pw_dup (pwent)))
- X return 0;
- X
- X pwf->pwf_changed = 1;
- X pwf->pwf_next = 0;
- X pwf->pwf_line = 0;
- X
- X if (pwf_tail)
- X pwf_tail->pwf_next = pwf;
- X
- X if (! pwf_head)
- X pwf_head = pwf;
- X
- X pwf_tail = pwf;
- X
- X return pw_changed = 1;
- X}
- X
- Xint
- Xpw_remove (name)
- Xchar *name;
- X{
- X struct pw_file_entry *pwf;
- X struct pw_file_entry *opwf;
- X
- X if (! isopen || open_modes == O_RDONLY) {
- X errno = EINVAL;
- X return 0;
- X }
- X for (opwf = 0, pwf = pwf_head;pwf != 0;
- X opwf = pwf, pwf = pwf->pwf_next) {
- X if (! pwf->pwf_entry)
- X continue;
- X
- X if (strcmp (name, pwf->pwf_entry->pw_name) != 0)
- X continue;
- X
- X if (pwf == pwf_cursor)
- X pwf_cursor = opwf;
- X
- X if (opwf != 0)
- X opwf->pwf_next = pwf->pwf_next;
- X else
- X pwf_head = pwf->pwf_next;
- X
- X if (pwf == pwf_tail)
- X pwf_tail = opwf;
- X
- X return pw_changed = 1;
- X }
- X errno = ENOENT;
- X return 0;
- X}
- X
- Xstruct passwd *
- Xpw_locate (name)
- Xchar *name;
- X{
- X struct pw_file_entry *pwf;
- X
- X if (! isopen) {
- X errno = EINVAL;
- X return 0;
- X }
- X for (pwf = pwf_head;pwf != 0;pwf = pwf->pwf_next) {
- X if (pwf->pwf_entry == 0)
- X continue;
- X
- X if (strcmp (name, pwf->pwf_entry->pw_name) == 0) {
- X pwf_cursor = pwf;
- X return pwf->pwf_entry;
- X }
- X }
- X errno = ENOENT;
- X return 0;
- X}
- X
- Xint
- Xpw_rewind ()
- X{
- X if (! isopen) {
- X errno = EINVAL;
- X return 0;
- X }
- X pwf_cursor = 0;
- X return 1;
- X}
- X
- Xstruct passwd *
- Xpw_next ()
- X{
- X if (! isopen) {
- X errno = EINVAL;
- X return 0;
- X }
- X if (pwf_cursor == 0)
- X pwf_cursor = pwf_head;
- X else
- X pwf_cursor = pwf_cursor->pwf_next;
- X
- X while (pwf_cursor) {
- X if (pwf_cursor->pwf_entry)
- X return pwf_cursor->pwf_entry;
- X
- X pwf_cursor = pwf_cursor->pwf_next;
- X }
- X return 0;
- X}
- END_OF_FILE
- if test 11226 -ne `wc -c <'pwio.c'`; then
- echo shar: \"'pwio.c'\" unpacked with wrong size!
- fi
- # end of 'pwio.c'
- fi
- if test -f 'shadowio.c' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'shadowio.c'\"
- else
- echo shar: Extracting \"'shadowio.c'\" \(10934 characters\)
- sed "s/^X//" >'shadowio.c' <<'END_OF_FILE'
- X/*
- X * Copyright 1990, 1991, John F. Haugh II
- X * All rights reserved.
- X *
- X * Permission is granted to copy and create derivative works for any
- X * non-commercial purpose, provided this copyright notice is preserved
- X * in all copies of source code, or included in human readable form
- X * and conspicuously displayed on all copies of object code or
- X * distribution media.
- X *
- X * This file implements a transaction oriented password database
- X * library. The password file is updated one entry at a time.
- X * After each transaction the file must be logically closed and
- X * transferred to the existing password file. The sequence of
- X * events is
- X *
- X * spw_lock -- lock shadow file
- X * spw_open -- logically open shadow file
- X * while transaction to process
- X * spw_(locate,update,remove) -- perform transaction
- X * done
- X * spw_close -- commit transactions
- X * spw_unlock -- remove shadow lock
- X */
- X
- X#ifndef lint
- Xstatic char sccsid[] = "@(#)shadowio.c 3.6 09:17:38 6/26/91";
- X#endif
- X
- X#include <sys/types.h>
- X#include <sys/stat.h>
- X#include <fcntl.h>
- X#include <errno.h>
- X#include <stdio.h>
- X#ifdef BSD
- X#include <strings.h>
- X#else
- X#include <string.h>
- X#endif
- X#include "shadow.h"
- X
- Xstatic int islocked;
- Xstatic int isopen;
- Xstatic int open_modes;
- Xstatic FILE *spwfp;
- X
- Xstruct spw_file_entry {
- X char *spwf_line;
- X int spwf_changed;
- X struct spwd *spwf_entry;
- X struct spw_file_entry *spwf_next;
- X};
- X
- Xstatic struct spw_file_entry *spwf_head;
- Xstatic struct spw_file_entry *spwf_tail;
- Xstatic struct spw_file_entry *spwf_cursor;
- Xstatic int sp_changed;
- Xstatic int lock_pid;
- X
- X#define SPW_LOCK "/etc/shadow.lock"
- X#define SPW_TEMP "/etc/spwd.%d"
- X#define SHADOW "/etc/shadow"
- X
- Xstatic char spw_filename[BUFSIZ] = SHADOW;
- X
- Xextern char *strdup();
- Xextern char *malloc();
- Xextern struct spwd *sgetspent();
- X
- X/*
- X * spw_dup - duplicate a shadow file entry
- X *
- X * spw_dup() accepts a pointer to a shadow file entry and
- X * returns a pointer to a shadow file entry in allocated
- X * memory.
- X */
- X
- Xstatic struct spwd *
- Xspw_dup (spwd)
- Xstruct spwd *spwd;
- X{
- X struct spwd *spw;
- X
- X if (! (spw = (struct spwd *) malloc (sizeof *spw)))
- X return 0;
- X
- X *spw = *spwd;
- X if ((spw->sp_namp = strdup (spwd->sp_namp)) == 0 ||
- X (spw->sp_pwdp = strdup (spwd->sp_pwdp)) == 0)
- X return 0;
- X
- X return spw;
- X}
- X
- X/*
- X * spw_free - free a dynamically allocated shadow file entry
- X *
- X * spw_free() frees up the memory which was allocated for the
- X * pointed to entry.
- X */
- X
- Xstatic void
- Xspw_free (spwd)
- Xstruct spwd *spwd;
- X{
- X free (spwd->sp_namp);
- X free (spwd->sp_pwdp);
- X}
- X
- X/*
- X * spw_name - change the name of the shadow password file
- X */
- X
- Xint
- Xspw_name (name)
- Xchar *name;
- X{
- X if (isopen || strlen (name) > (BUFSIZ-10))
- X return -1;
- X
- X strcpy (spw_filename, name);
- X return 0;
- X}
- X
- X/*
- X * spw_lock - lock a password file
- X *
- X * spw_lock() encapsulates the lock operation. it returns
- X * TRUE or FALSE depending on the password file being
- X * properly locked. the lock is set by creating a semaphore
- X * file, SPW_LOCK.
- X */
- X
- Xint
- Xspw_lock ()
- X{
- X int fd;
- X int pid;
- X int len;
- X char file[BUFSIZ];
- X char buf[32];
- X struct stat sb;
- X
- X if (islocked)
- X return 1;
- X
- X if (strcmp (spw_filename, SHADOW) != 0)
- X return 0;
- X
- X /*
- X * Create a lock file which can be switched into place
- X */
- X
- X sprintf (file, SPW_TEMP, lock_pid = getpid ());
- X if ((fd = open (file, O_CREAT|O_EXCL|O_WRONLY, 0600)) == -1)
- X return 0;
- X
- X sprintf (buf, "%d", lock_pid);
- X if (write (fd, buf, strlen (buf) + 1) != strlen (buf) + 1) {
- X (void) close (fd);
- X (void) unlink (file);
- X return 0;
- X }
- X close (fd);
- X
- X /*
- X * Simple case first -
- X * Link fails (in a sane environment ...) if the target
- X * exists already. So we try to switch in a new lock
- X * file. If that succeeds, we assume we have the only
- X * valid lock. Needs work for NFS where this assumption
- X * may not hold. The simple hack is to check the link
- X * count on the source file, which should be 2 iff the
- X * link =really= worked.
- X */
- X
- X if (link (file, SPW_LOCK) == 0) {
- X if (stat (file, &sb) != 0)
- X return 0;
- X
- X if (sb.st_nlink != 2)
- X return 0;
- X
- X (void) unlink (file);
- X islocked = 1;
- X return 1;
- X }
- X
- X /*
- X * Invalid lock test -
- X * Open the lock file and see if the lock is valid.
- X * The PID of the lock file is checked, and if the PID
- X * is not valid, the lock file is removed. If the unlink
- X * of the lock file fails, it should mean that someone
- X * else is executing this code. They will get success,
- X * and we will fail.
- X */
- X
- X if ((fd = open (SPW_LOCK, O_RDWR)) == -1 ||
- X (len = read (fd, buf, BUFSIZ)) <= 0) {
- X errno = EINVAL;
- X return 0;
- X }
- X buf[len] = '\0';
- X if ((pid = strtol (buf, (char **) 0, 10)) == 0) {
- X errno = EINVAL;
- X return 0;
- X }
- X if (kill (pid, 0) == 0) {
- X errno = EEXIST;
- X return 0;
- X }
- X if (unlink (SPW_LOCK)) {
- X (void) close (fd);
- X (void) unlink (file);
- X
- X return 0;
- X }
- X
- X /*
- X * Re-try lock -
- X * The invalid lock has now been removed and I should
- X * be able to acquire a lock for myself just fine. If
- X * this fails there will be no retry. The link count
- X * test here makes certain someone executing the previous
- X * block of code didn't just remove the lock we just
- X * linked to.
- X */
- X
- X if (link (file, SPW_LOCK) == 0) {
- X if (stat (file, &sb) != 0)
- X return 0;
- X
- X if (sb.st_nlink != 2)
- X return 0;
- X
- X (void) unlink (file);
- X islocked = 1;
- X return 1;
- X }
- X (void) unlink (file);
- X return 0;
- X}
- X
- X/*
- X * spw_unlock - logically unlock a shadow file
- X *
- X * spw_unlock() removes the lock which was set by an earlier
- X * invocation of spw_lock().
- X */
- X
- Xint
- Xspw_unlock ()
- X{
- X if (isopen) {
- X open_modes = O_RDONLY;
- X if (! spw_close ())
- X return 0;
- X }
- X if (islocked) {
- X islocked = 0;
- X if (lock_pid != getpid ())
- X return 0;
- X
- X (void) unlink (SPW_LOCK);
- X return 1;
- X }
- X return 0;
- X}
- X
- X/*
- X * spw_open - open a password file
- X *
- X * spw_open() encapsulates the open operation. it returns
- X * TRUE or FALSE depending on the shadow file being
- X * properly opened.
- X */
- X
- Xint
- Xspw_open (mode)
- Xint mode;
- X{
- X char buf[BUFSIZ];
- X char *cp;
- X struct spw_file_entry *spwf;
- X struct spwd *spwd;
- X
- X if (isopen || (mode != O_RDONLY && mode != O_RDWR))
- X return 0;
- X
- X if (mode != O_RDONLY && ! islocked &&
- X strcmp (spw_filename, SHADOW) == 0)
- X return 0;
- X
- X if ((spwfp = fopen (spw_filename, mode == O_RDONLY ? "r":"r+")) == 0)
- X return 0;
- X
- X spwf_head = spwf_tail = spwf_cursor = 0;
- X sp_changed = 0;
- X
- X while (fgets (buf, sizeof buf, spwfp) != (char *) 0) {
- X if (cp = strrchr (buf, '\n'))
- X *cp = '\0';
- X
- X if (! (spwf = (struct spw_file_entry *) malloc (sizeof *spwf)))
- X return 0;
- X
- X spwf->spwf_changed = 0;
- X spwf->spwf_line = strdup (buf);
- X if ((spwd = sgetspent (buf)) && ! (spwd = spw_dup (spwd)))
- X return 0;
- X
- X spwf->spwf_entry = spwd;
- X
- X if (spwf_head == 0) {
- X spwf_head = spwf_tail = spwf;
- X spwf->spwf_next = 0;
- X } else {
- X spwf_tail->spwf_next = spwf;
- X spwf->spwf_next = 0;
- X spwf_tail = spwf;
- X }
- X }
- X isopen++;
- X open_modes = mode;
- X
- X return 1;
- X}
- X
- X/*
- X * spw_close - close the password file
- X *
- X * spw_close() outputs any modified password file entries and
- X * frees any allocated memory.
- X */
- X
- Xint
- Xspw_close ()
- X{
- X char backup[BUFSIZ];
- X int mask;
- X int c;
- X int errors = 0;
- X FILE *bkfp;
- X struct spw_file_entry *spwf;
- X struct stat sb;
- X
- X if (! isopen) {
- X errno = EINVAL;
- X return 0;
- X }
- X if (islocked && lock_pid != getpid ()) {
- X isopen = 0;
- X islocked = 0;
- X errno = EACCES;
- X return 0;
- X }
- X strcpy (backup, spw_filename);
- X strcat (backup, "-");
- X
- X if (open_modes == O_RDWR && sp_changed) {
- X mask = umask (0377);
- X if ((bkfp = fopen (backup, "w")) == 0) {
- X umask (mask);
- X return 0;
- X }
- X umask (mask);
- X fstat (fileno (spwfp), &sb);
- X chown (backup, sb.st_uid, sb.st_gid);
- X
- X rewind (spwfp);
- X while ((c = getc (spwfp)) != EOF) {
- X if (putc (c, bkfp) == EOF) {
- X fclose (bkfp);
- X return 0;
- X }
- X }
- X if (fclose (bkfp))
- X return 0;
- X
- X isopen = 0;
- X (void) fclose (spwfp);
- X
- X mask = umask (0377);
- X if (! (spwfp = fopen (spw_filename, "w"))) {
- X umask (mask);
- X return 0;
- X }
- X umask (mask);
- X
- X for (spwf = spwf_head;errors == 0 && spwf;
- X spwf = spwf->spwf_next) {
- X if (spwf->spwf_changed) {
- X if (putspent (spwf->spwf_entry, spwfp))
- X errors++;
- X } else {
- X if (fputs (spwf->spwf_line, spwfp) == EOF)
- X errors++;
- X if (putc ('\n', spwfp) == EOF)
- X errors++;
- X }
- X }
- X if (fflush (spwfp))
- X errors++;
- X
- X if (errors) {
- X unlink (spw_filename);
- X link (backup, spw_filename);
- X unlink (backup);
- X return 0;
- X }
- X }
- X if (fclose (spwfp))
- X return 0;
- X
- X spwfp = 0;
- X
- X while (spwf_head != 0) {
- X spwf = spwf_head;
- X spwf_head = spwf->spwf_next;
- X
- X if (spwf->spwf_entry) {
- X spw_free (spwf->spwf_entry);
- X free (spwf->spwf_entry);
- X }
- X if (spwf->spwf_line)
- X free (spwf->spwf_line);
- X
- X free (spwf);
- X }
- X spwf_tail = 0;
- X isopen = 0;
- X return 1;
- X}
- X
- Xint
- Xspw_update (spwd)
- Xstruct spwd *spwd;
- X{
- X struct spw_file_entry *spwf;
- X struct spwd *nspwd;
- X
- X if (! isopen || open_modes == O_RDONLY) {
- X errno = EINVAL;
- X return 0;
- X }
- X for (spwf = spwf_head;spwf != 0;spwf = spwf->spwf_next) {
- X if (spwf->spwf_entry == 0)
- X continue;
- X
- X if (strcmp (spwd->sp_namp, spwf->spwf_entry->sp_namp) != 0)
- X continue;
- X
- X if (! (nspwd = spw_dup (spwd)))
- X return 0;
- X else {
- X spw_free (spwf->spwf_entry);
- X *(spwf->spwf_entry) = *nspwd;
- X }
- X spwf->spwf_changed = 1;
- X spwf_cursor = spwf;
- X return sp_changed = 1;
- X }
- X spwf = (struct spw_file_entry *) malloc (sizeof *spwf);
- X if (! (spwf->spwf_entry = spw_dup (spwd)))
- X return 0;
- X
- X spwf->spwf_changed = 1;
- X spwf->spwf_next = 0;
- X spwf->spwf_line = 0;
- X
- X if (spwf_tail)
- X spwf_tail->spwf_next = spwf;
- X
- X if (! spwf_head)
- X spwf_head = spwf;
- X
- X spwf_tail = spwf;
- X
- X return sp_changed = 1;
- X}
- X
- Xint
- Xspw_remove (name)
- Xchar *name;
- X{
- X struct spw_file_entry *spwf;
- X struct spw_file_entry *ospwf;
- X
- X if (! isopen || open_modes == O_RDONLY) {
- X errno = EINVAL;
- X return 0;
- X }
- X for (ospwf = 0, spwf = spwf_head;spwf != 0;
- X ospwf = spwf, spwf = spwf->spwf_next) {
- X if (! spwf->spwf_entry)
- X continue;
- X
- X if (strcmp (name, spwf->spwf_entry->sp_namp) != 0)
- X continue;
- X
- X if (spwf == spwf_cursor)
- X spwf_cursor = ospwf;
- X
- X if (ospwf != 0)
- X ospwf->spwf_next = spwf->spwf_next;
- X else
- X spwf_head = spwf->spwf_next;
- X
- X if (spwf == spwf_tail)
- X spwf_tail = ospwf;
- X
- X return sp_changed = 1;
- X }
- X errno = ENOENT;
- X return 0;
- X}
- X
- Xstruct spwd *
- Xspw_locate (name)
- Xchar *name;
- X{
- X struct spw_file_entry *spwf;
- X
- X if (! isopen) {
- X errno = EINVAL;
- X return 0;
- X }
- X for (spwf = spwf_head;spwf != 0;spwf = spwf->spwf_next) {
- X if (spwf->spwf_entry == 0)
- X continue;
- X
- X if (strcmp (name, spwf->spwf_entry->sp_namp) == 0) {
- X spwf_cursor = spwf;
- X return spwf->spwf_entry;
- X }
- X }
- X errno = ENOENT;
- X return 0;
- X}
- X
- Xint
- Xspw_rewind ()
- X{
- X if (! isopen) {
- X errno = EINVAL;
- X return 0;
- X }
- X spwf_cursor = 0;
- X return 1;
- X}
- X
- Xstruct spwd *
- Xspw_next ()
- X{
- X if (! isopen) {
- X errno = EINVAL;
- X return 0;
- X }
- X if (spwf_cursor == 0)
- X spwf_cursor = spwf_head;
- X else
- X spwf_cursor = spwf_cursor->spwf_next;
- X
- X while (spwf_cursor) {
- X if (spwf_cursor->spwf_entry)
- X return spwf_cursor->spwf_entry;
- X
- X spwf_cursor = spwf_cursor->spwf_next;
- X }
- X return 0;
- X}
- END_OF_FILE
- if test 10934 -ne `wc -c <'shadowio.c'`; then
- echo shar: \"'shadowio.c'\" unpacked with wrong size!
- fi
- # end of 'shadowio.c'
- fi
- echo shar: End of archive 5 \(of 11\).
- cp /dev/null ark5isdone
- MISSING=""
- for I in 1 2 3 4 5 6 7 8 9 10 11 ; do
- if test ! -f ark${I}isdone ; then
- MISSING="${MISSING} ${I}"
- fi
- done
- if test "${MISSING}" = "" ; then
- echo You have unpacked all 11 archives.
- rm -f ark[1-9]isdone ark[1-9][0-9]isdone
- else
- echo You still must unpack the following archives:
- echo " " ${MISSING}
- fi
- exit 0
- exit 0 # Just in case...
-